Now we only have one problem left. We need to have a function which can generate the events which drive the system. Specifically it needs to be able to identify dots, dashes, spaces and stuck.
Space
We can identify a space because we have a particular time of inactivity on the line. If, after the given time, we have not seen the key down we can regard the input as a space.
Dot
If I get a key pressed I can time the length of the time the key is down. If it is raised before a certain limit I can regard the event as a "dot".
Dash
Dash is the same as dot, but the time the key is to be held down is greater.
Stuck
Stuck is the one that nobody considers, If the key is held down for greater than a certain time I must regard the event as a stuck down one and must return that.
On the right you can see the code which I wrote to implement this. I am using the familiar trick of setting the time running and then using it to generate counts which I can check against. There are a number of reasons why I work this way. I could do the timing using loops in the function itself, but this would be difficult because the speed of the PICmicro would mean that I would count so fast that the count values would get very big and be hard to manage. Also, if I count inside a loop, the speed of the counter is determined by the speed of the code. This means that if I change the contents of the loop, I will change the rate at which the counter counts.
The first thing my program does is wait for the button to go down. If the button isn't pressed in a given time period I call the entry a "space" and return this. Once I have noticed a button going down I have either a "dot", a "dash" or a "stuck" I time the length of the pulse to find out. If the counter reaches the stuck value I return that. If it is less than the dot value I return a dot. Otherwise I assume that we have a dash and return that.
This code works well. I am not to happy with the timing values, in that they suit a very slow morse operator, but these can be adjusted by changing the #defined
constants.
If you were generating a proper morse trainer you might be inclined to store the speed values in EEPROM so that a system can be configured for a particular user. Another technique is to actually time the pulses until your program can tell the difference between dots and dashes. Real morse operators don't use a simple key, they use a mechanical device which can produce streams of dots and dashes to order. This means that the signal is quite consistently timed and so your program could "lock on" to the speed of the output.
My final (and working) program is in Exercise 9.3
The first thing I am going to do is get the program reading from the input ports and displaying on the LCD. This will convince me that I can drive the LCD and read the ports fast enough. I am also going to use the LCD library we created in Lab 5. What I want is a program which will read PORTA bit 0 and display either "up" or "down" depending on the state of the pin. The "up" or "down" message must be displayed in the top left hand corner of the display. On the right hand side you can see a more detailed set of requirements along with some hints.
/* times in 200ths of a second */
/* for dots, dashes and spaces */
#define DOT_LENGTH 50
#define DASH_LENGTH 100
#define SPACE_LENGTH 150
#define STUCK_LENGTH 200
/* using PORTA bit 0 */
#define KEY_BIT 0x01
unsigned char get_morse_key ( void )
{
/* set the clock at 0 */
/* wait for a key down */
/* time_count is updated by */
/* the interrupt handler */
time_count = 0 ;
while ( time_count < SPACE_LENGTH )
{
if ( PORTAinputs & KEY_BIT )
{
/* quit the loop when */
/* the key is pressed */
break ;
}
}
/* if the time count has */
/* reached SPACE_LENGTH we */
/* have a space */
if ( time_count >= SPACE_LENGTH )
{
return SPACE_EVENT;
}
/* must now time the length of */
/* of the key down period */
time_count = 0 ;
while ( time_count < STUCK_LENGTH )
{
if ( ( PORTAinputs & KEY_BIT ) == 0 )
{
/* quit the loop when */
/* the key is released */
break ;
}
}
/* if time_count has reached */
/* stuck length return the */
/* stuck down message */
if ( time_count >= STUCK_LENGTH )
{
return STUCK_EVENT ;
}
/* if the time_count is less */
/* than dot - return dot */
if ( time_count < DOT_LENGTH )
{
return DOT_EVENT ;
}
/* if we get here we must have */
/* a dash */
return DASH_EVENT ;
}